#include <p32xxxx.h>
#include "Button.h"
#include "Slider.h"
#include "AnalogClock.h"
#include "StaticText.h"
#include "CheckBox.h"
#include "HardwareProfile.h"
#include "GOL.h"
#include <stdlib.h>
#include "timer.h"
#include "XPT2046.h"

#pragma config FPLLMUL  = MUL_20        // PLL Multiplier        (8MHz / 2 = 4MHz x 20 = 80MHz)
#pragma config UPLLIDIV = DIV_2         // USB PLL Input Divider (8MHz Clock)
#pragma config UPLLEN   = ON        	// USB PLL Enabled
#pragma config FPLLIDIV = DIV_2         // PLL Input Divider	 (8MHz Clock)
#pragma config FPLLODIV = DIV_1         // PLL Output Divider
#pragma config FPBDIV   = DIV_1         // Peripheral Clock divisor
#pragma config FWDTEN   = OFF           // Watchdog Timer
#pragma config WDTPS    = PS1           // Watchdog Timer Postscale
#pragma config FCKSM    = CSDCMD        // Clock Switching & Fail Safe Clock Monitor
#pragma config OSCIOFNC = OFF           // CLKO Enable
#pragma config POSCMOD  = HS            // Primary Oscillator
#pragma config IESO     = OFF           // Internal/External Switch-over
#pragma config FSOSCEN  = OFF           // Secondary Oscillator Enable (KLO was off)
#pragma config FNOSC    = PRIPLL        // Oscillator Selection
#pragma config CP       = OFF           // Code Protect
#pragma config BWP      = OFF           // Boot Flash Write Protect
#pragma config PWP      = OFF           // Program Flash Write Protect
#pragma config ICESEL   = ICS_PGx2      // ICE/ICD Comm Channel Select
#pragma config DEBUG    = ON            // Background Debugger Enable

// Unique user defined IDs
#define btn1ID  0
#define btn2ID  1
#define sld1ID  2
#define ac1ID   3
#define st1ID   4
#define cb1ID   5

#define TMR4FREQ 10

#define TMR4DELAY 100/TMR4FREQ

#define intToBcd(number)    ((number/10)<<4) + number%10;
#define bcdToInt(number)    (number & 0x0f)+(((number & 0xf0) >> 4)*10)

unsigned int tmr4Counter = 0;

GOL_SCHEME *altScheme;

void main() {

    OSCCONbits.SOSCEN = 1;  // Enable the external clock source
    delayMs(10);
    
    // Initialise the Graphic Object Layer (GOL)
    GOLInit();

    // Modify the colour theme of the display.
    altScheme = GOLCreateScheme();  // Create alternative style
    altScheme->Color0 = LIGHTBLUE;
    altScheme->Color1 = BLUE;
    altScheme->TextColor0 = WHITE;  // Set text color 0
    altScheme->TextColor1 = WHITE;  // Set text color 1 i.e. when button pressed
    altScheme->CommonBkColor = BLACK;
    _pDefaultGolScheme = altScheme; // Comment this out if you want the default scheme

    touchScrInit(ENABLE);   // Initialise the touch screen with the interrupt enabled
    consoleInit();          // Initialises the uart port for debug messaeges
    intialiseLeds();
    intialiseSwitches();



    // Intialise the real time clock
    rtccTime tm;
    tm.hour = intToBcd(22);     //hr = 22, min = 17
    tm.min = intToBcd(17);
    tm.sec = intToBcd(51);

    rtccDate dt;
    dt.wday = 03;
    dt.mday = intToBcd(25);
    dt.mon = intToBcd(7);
    dt.year = intToBcd(12);

    RtccOpen(tm.l, dt.l, 10);

    // Set up timer 1 to flash the LED at 1Hz, this uses the same external clock as the rtcc
    OpenTimer1(T1_ON | T1_PS_1_1 | T1_SOURCE_EXT, 32768);
    IEC0bits.T1IE = 1;
    SetPriorityIntT1(T1_INT_PRIOR_3);

    // Set up timer 4 for graphics refresh
    OpenTimer4(T4_ON | T4_PS_1_256 | T1_SOURCE_INT, (FCY / 256) / 100);
    IEC0bits.T4IE = 1;
    SetPriorityIntT4(T4_INT_PRIOR_3);

    DisplayBacklightOn();

    // Clear screen
    SetColor(BLACK);
    Bar(0, 0, 239, 319);

    // Initiate touch screen calibration
    touchScrCalibrate();

    // A few examples of the objects/widgets that can be drawn
    BtnCreate(btn1ID, 1, 250, 120, 285, 5, BTN_DRAW, NULL, "LEFT", NULL);
    BtnCreate(btn2ID, 130, 250, 239, 285, 5, BTN_DRAW, NULL, "RIGHT", NULL);
    SldCreate(sld1ID, 1, 290, 239, 319, SLD_DRAW, 100, 5, 50, NULL);
    CbCreate(cb1ID, 120, 150, 159, 190, CB_DRAW, "LED2", NULL);

    ANALOGCLOCK *ac;
    ac = AcCreate(ac1ID, 120, 5, 235, 115, tm.hour, tm.min, 55, 0, AC_DRAW, NULL, NULL);

    // Initialise the GOL messages that will be exchanged between components
    GOL_MSG msg;
    msg.type = TYPE_TOUCHSCREEN;

    INTEnableSystemMultiVectoredInt();

    // Clear screen
    SetColor(BLACK);
    Bar(0, 0, 239, 319);

    // Creates a string that will be used to display messages on the screen
    char string[25];
    STATICTEXT *st;
    st = StCreate(st1ID, 10, 200, 220, 230, SLD_DRAW, "Hello World!", NULL);

    while (1) {
        
        delayMs(200);

        // Get the current time, update the analog clock and then flag that it needs redrawing.
        if(tm.l != RtccGetTime())
        {
            tm.l = RtccGetTime();
            AcSetSecond(ac, bcdToInt(tm.sec));
            AcSetMinute(ac, bcdToInt(tm.min));
            AcSetHour(ac, bcdToInt(tm.hour));
            SetState(ac, AC_DRAW);
        }

    }
}

/*
 * Function: WORD GOLDrawCallback()
 * Output: if the function returns non-zero the draw control will be passed to GOL
 * Overview: this function must be implemented by user. GOLDraw() function calls it each
 *           time when GOL objects drawing is completed. User drawing should be done here.
 *           GOL will not change color, line type and clipping region settings while
 *           this function returns zero.
 */

WORD GOLDrawCallback() {

    return (1);
}

/*
 * Function: WORD GOLMsgCallback(WORD objMsg, OBJ_HEADER* pObj, GOL_MSG* pMsg)
 * Input: objMsg - translated message for the object,
 *        pObj - pointer to the object,
 *        pMsg - pointer to the non-translated, raw GOL message
 * Output: if the function returns non-zero the message will be processed by default
 * Overview: this function must be implemented by user. GOLMsg() function calls it each
 *            time the valid message for the object received
 */

WORD GOLMsgCallback(WORD objMsg, OBJ_HEADER* pObj, GOL_MSG* pMsg) {

    WORD objectID;
    SLIDER *pSldObj;
    CHECKBOX *pCbObj;

    // Get the ID of the object currently being evaluated
    objectID = GetObjID(pObj);
    // Check if message is for 1st Button
    if (objectID == btn1ID) {
        // This message is for 1st Button
        // Check if button is pressed
        // objMsg is the translated message from the object
        if (objMsg == BTN_MSG_PRESSED) {
            // Button is pressed decrement the slider position
            // Slider pointer is retrieved for slider named ID_SLD1
            pSldObj = (SLIDER*) GOLFindObject(sld1ID);
            // Position is decremented by Slider's current page value
            SldDecPos(pSldObj);
            // Set the state to redraw slider thumb to reflect new position
            SetState(pSldObj, SLD_DRAW_THUMB);
        }
    }
    // Check if message is for 2nd Button
    if (objectID == btn2ID) {
        // This message is for 1st Button
        // Check if button is pressed
        if (objMsg == BTN_MSG_PRESSED) {
            // If button is pressed increment the slider position
            // Slider pointer is retrieved for slider named ID_SLD1
            pSldObj = (SLIDER*) GOLFindObject(sld1ID);
            // Position is incremented by Slider's current page value
            SldIncPos(pSldObj);
            // Set the state to redraw slider thumb to reflect new position
            SetState(pSldObj, SLD_DRAW_THUMB);
        }
    }

    // Check if message is for check box
    if (objectID == cb1ID) {

        pCbObj = (CHECKBOX*) GOLFindObject(cb1ID);

        SetState(pCbObj, CB_DRAW_CHECK);

        unsigned char test = ((pCbObj->hdr.state) >> 2)&0x000f;

        LED2 = test;
    }

    // We must return 1 here to update on the buttons (press and release effects)
    return 1;
}

void __attribute((interrupt(ipl3), vector(_TIMER_1_VECTOR), nomips16)) _Timer1Handler(void) {

    // Flash LED

    LED4 = 0;
    delayUs(25);
    LED4 = 1;

    IFS0bits.T1IF = 0;
    IEC0bits.T1IE = 1;
}

void __attribute((interrupt(ipl3), vector(_TIMER_4_VECTOR), nomips16)) _Timer4Handler(void) {

    // Redraw graphics

    IFS0bits.T4IF = 0;

    if (tmr4Counter++ < TMR4DELAY)
        return;

    tmr4Counter = 0;

    GOLDraw();
}

